/**
 * @export
 * @class Shield
 * @classdesc 透明护罩组件
 * @property {Object} 地图容器 - SchoolLab实例
 * @property {String} name - 名称
 * @property {String} color - 颜色
 * @property {Number} opacity - 透明度
 * @property {Number} radius - 半径
 * @property {Number} renderOrder - 层叠顺序
 * @property {Number} coeficient - 渐变系数
 * @property {Number} power - 渐变强度
 * @example
 * var shield = new Shield(viewer, {
 *   radius: 4,
 *   color: '#ff0000',
 *   opacity: 0.5,
 *   renderOrder: 20,
 *   power: 1.4,
 *   coeficient: 1,
 *   name: 'shield'
 * })
 */
import { extend, lngLatToWorld, transformCoordinate } from './util'
import { TimelineLite, Linear } from 'gsap'
import Feature from './Feature'

export default class Shield {
  constructor(viewer, options) {
    const opts = extend({
      name: "shield",
      color: "#ffffff",
      opacity: 1,
      radius: 1,
      coeficient: 1,
      power: 1.4,
      renderOrder: 1
    }, options)

    /** @member {SchoolLab} - 地图容器 */
    this.viewer = viewer
    
    /** @member {String} - 名称 */
    this.name = opts.name
    
    /** @member {Color} - 颜色 */
    this.color = opts.color
    
    /** @member {Number} - 透明度 */
    this.opacity = opts.opacity
    
    /** @member {Number} - 半径 */
    this.radius = opts.radius
    
    /** @member {Number} - 层叠顺序 */
    this.renderOrder = opts.renderOrder
    
    /** @member {Number} - 渐变系数 */
    this.coeficient = opts.coeficient
    
    /** @member {Number} - 渐变强度 */
    this.power = opts.power
    
    /** @member {THREE.Mesh} - mesh对象 */
    this.entity = null

    Feature.apply(this)

    this._init()
  }

  // 初始化组件
  _init() {
    let geometry = this._initGeometry()
    let material = this._initMaterial()

    const mesh = new THREE.Mesh(geometry, material)
    mesh.name = this.name
    mesh.renderOrder = this.renderOrder
    mesh.scale.set(0.0001, 0.0001, 0.0001)

    this.entity = mesh
    this.viewer.world.add(mesh)
  }

  // 初始化几何体
  _initGeometry() {
    const geometry = new THREE.SphereBufferGeometry(this.radius, 64, 64)
    return geometry
  }

  // 初始化材质
  _initMaterial() {
    const uniforms = {
      coeficient: { type: 'f', value: this.coeficient },
      power: { type: 'f', value: this.power },
      color: { type: "c", value: new THREE.Color(this.color) },
      opacity: { type: "f", value: this.opacity }
    }

    let vs = this._initVS()
    let fs = this._initFS()
    const material = new THREE.ShaderMaterial({
      uniforms: uniforms,
      vertexShader: vs,
      fragmentShader: fs,
      transparent: true,
      depthWrite: false,
      depthTest: true,
      blending: THREE.AdditiveBlending,
      side: THREE.FrontSide
    })

    return material
  }

  // 初始化vertexShader
  _initVS() {
    const vs = `
      precision lowp float;
      precision lowp int;
      varying vec3   vVertexWorldPosition;
      varying vec3  vVertexNormal;
      
      varying vec2 vUv;
      
      void main(){
        vUv = uv;
        vVertexNormal  = normalize(normalMatrix * normal);
        vVertexWorldPosition   = (modelMatrix * vec4(position, 1.0)).xyz;
      
        gl_Position    = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
      }
    `
    return vs
  }

  // 初始化fragmentShader
  _initFS() {
    const fs = `
      precision lowp float;
      precision lowp int;
      uniform vec3 color;
      uniform float coeficient;
      uniform float power;
      
      varying vec2 vUv;
      varying vec3 vVertexNormal;
      varying vec3 vVertexWorldPosition;
      
      varying vec4 vFragColor;
      
      void main(){
        vec2 uv = vUv;
        vec3 worldCameraToVertex = vVertexWorldPosition - cameraPosition;
        vec3 viewCameraToVertex = (viewMatrix * vec4(worldCameraToVertex, 0.0)).xyz;
        viewCameraToVertex = normalize(viewCameraToVertex);
        float intensity = pow(coeficient + dot(vVertexNormal, viewCameraToVertex), power);
        gl_FragColor = vec4(color, intensity + 0.1);
      }
    `
    return fs
  }

  // 设置经纬度坐标
  setGisPosition(lngLat, altitude) {
    this.entity.visible = false
    let world = lngLatToWorld(lngLat)
    let format = transformCoordinate(this.viewer.gisCenter, world)
    this.entity.position.set(format.x, format.y, altitude)
    this.entity.visible = true
  }

  // 设置世界坐标
  setPosition(vec2, altitude) {
    this.entity.visible = false
    this.entity.position.set(vec2.x, vec2.y, altitude)
    this.entity.visible = true
  }

  // 设置半径
  setRadius(radius) {
    this.entity.geometry.dispose()
    this.entity.geometry = new THREE.SphereBufferGeometry(radius, 64, 64)
    this.entity.geometry.needsUpdate = true
  }

  // 组件显示
  show(callback, ...args) {
    let self = this
    let tl = new TimelineLite({
      paused: !1,
      delay: 0,
      repeat: 0,
      yoyo: true,
      onComplete: function() {
        tl = null
        // args[0]: floor, args[1]: path
        callback(args[0], args[1])
      },
      onUpdate: function() {
        self.entity.scale.set(scale.x, scale.y, scale.z)
      }
    })
    let scale = {
      x: 0.0001,
      y: 0.0001,
      z: 0.0001
    }

    tl.to(scale, 0.5, {
      x: 1,
      y: 1,
      z: 1,
      ease: Linear.none
    }, 0)
  }

  // 组件隐藏
  hide() {
    let self = this
    let tl = new TimelineLite({
      paused: !1,
      delay: 0,
      repeat: 0,
      yoyo: true,
      onComplete: function() {
        tl = null
      },
      onUpdate: function() {
        self.entity.scale.set(scale.x, scale.y, scale.z)
      }
    })
    let scale = {
      x: 1,
      y: 1,
      z: 1
    }

    tl.to(scale, 0.5, {
      x: 0.0001,
      y: 0.0001,
      z: 0.0001,
      ease: Linear.none
    }, 0)
  }

  // 组件销毁
  destroy() {
    this._disposeHierarchy(this.entity, this._dispose)
    this.viewer.world.remove(this.entity)
    this.entity = null
  }
}
